#pragma once
#include <stdint.h>
#include <vector>
#include <string>
#include <tuple>
#include <functional>
#include <zmq.hpp>

namespace RobotControl{
namespace Common{

/// 使用流程
/// 构造 --->>> addSubscriber()/addReply() ---->>> start() --->>> 线程一直run()
/// NOTE: 注意此类非线程安全

/// \brief 处理消息订阅、应答
class MsgServer
{
public:
	/// \brief 订阅消息回调
	typedef std::function<void(zmq::message_t &sub)>  SubCallback_t;

	/// \brief 应答回调
	/// \param req: request请求的数据
	/// \param rep: reply应答的数据
	typedef std::function<void(zmq::message_t &req, zmq::message_t &rep)>  RepCallback_t;	

public:
	/// \brief 组件构造
	MsgServer(zmq::context_t *ctx);

	/// \brief 析构
	virtual ~MsgServer()
	{
		if (m_pollers) delete m_pollers;
	}

	/// \brief 运行消息回调, 处理消息的订阅和回调
	/// \param[in] timeout 超时时间 -1表示不超时，>0表示超时的ms数
	/// note: 在所有订阅消息、应答处理添加完成后在一个线程执行run
	/// 暂时不支持动态添加，也就是一边run，一边addSub等
	void run(const int32_t timeout = -1);

	/// \brief 添加订阅
	/// \param[in] topic: 订阅消息
	/// \param[in] callback: 回调方法
	bool addSubscriber(const std::string &topic, const SubCallback_t &callback);

	/// \brief 添加应答
	/// \param[in] topic: 响应消息
	/// \param[in] callback: 回调方法
	bool addReply(const std::string &topic, const RepCallback_t &callback);

	/// \brief 启动
	bool start();

private:
	/// \brief 类型
	enum Type_t
	{
		Sub = 0,	///< 订阅
		Rep = 1,	///< 应答
	};

private:
	zmq::context_t *m_ctx;						///< zmq上下文
	std::vector<zmq::socket_t> m_sockets;		///< 所有socket
	std::vector<std::tuple<SubCallback_t, RepCallback_t>> m_callbacks;
	std::vector<Type_t> m_types;				///< 类型
	zmq_pollitem_t *m_pollers;					///< zmq poller
};

}	// Common
}	// RobotControl
